-module(gproxy).
-export([start/1,gateway/1,rpc/2,server_change/2, code_change/2]).

%% TODO: 
%%  - balance: gloop([S1, S2, S3])
%%  - backend failover

%% start the server (backend)
start(Fun) ->
  spawn(fun() -> loop(Fun) end).

%% start the proxy (frontend)
gateway(Server) ->
  spawn(fun() -> gloop(Server) end).

%% Pid can be gateway or server 
rpc(Pid, Q) ->
  Pid ! {self(), Q},
  receive 
    {Pid, Reply} -> 
      Reply
  end.

%% change the backend
%% send to the GATEWAY
server_change(Gw,Server1) ->
  Gw ! {be_change,Server1}.

%% function code change
%% send to the SERVER
code_change(Server, Fun1) ->
  Server ! {swap_code,Fun1}.

%% server loop
loop(Fun) ->
  receive
    {swap_code,Fun1} ->
      loop(Fun1);
    %% direct request
    {From, X} ->
      From ! {self(), Fun(X)},
      loop(Fun);
    %% request via gateway
    {Gw, From, X} ->
      Gw ! {served, From, self(), Fun(X)},
      loop(Fun)
  end.

%% gateway loop
gloop(Backend) ->
  receive
    {be_change,BE1} ->
      gloop(BE1);
    {Client, X} ->
      Backend ! {self(), Client, X},
      gloop(Backend);
    {served, Client, Server, X} ->
      Client ! {self(), X},
      gloop(Backend)
  end.
